package proxyc

import (
	"gitee.com/yysf-xin/dproxy/pkg/app"
	"gitee.com/yysf-xin/dproxy/pkg/db"
	"gitee.com/yysf-xin/dproxy/pkg/model"
	"github.com/armon/go-socks5"
	"github.com/go-chi/chi/v5"
	"github.com/soheilhy/cmux"
	"golang.org/x/net/proxy"
	"net"
	"net/http"
	"time"
)

type Socket5Control struct {
	Conf    *app.Config
	service *app.Services
	sv      *socks5.Server
	stopped bool
	l       net.Listener
}

func (c *Socket5Control) InitRoute(r chi.Router) {
	r.Post("/enable", app.JsonHttp(func() interface{} {
		return &model.Enable{}
	}, c.handlerEnable))
}

func (c *Socket5Control) handlerEnable(_ http.ResponseWriter, _ *http.Request, i interface{}) (r interface{}, err error) {
	c.Conf.File.EnableProxy = i.(*model.Enable).Enabled
	if c.Conf.File.EnableProxy && c.stopped {
		go c.Start()
	}

	return
}

func (c *Socket5Control) Start() (err error) {
	c.stopped = false
	for {
		conn, err := c.l.Accept()
		if err != nil {
			break
		}
		if conn == nil {
			continue
		}
		if !c.Conf.File.EnableProxy {
			time.Sleep(15 * time.Second)
			err = conn.Close()
			continue
		}
		go c.sv.ServeConn(conn)
	}
	c.stopped = true
	return
}

func NewSocket5Control(DB *db.Client, cMux cmux.CMux, Conf *app.Config, service *app.Services, d proxy.Dialer) (c *Socket5Control, err error) {
	dialer := d.(proxy.ContextDialer)
	conf := &socks5.Config{
		Dial: dialer.DialContext,
	}
	sv, err := socks5.New(conf)
	if err == nil {
		c = &Socket5Control{
			Conf:    Conf,
			sv:      sv,
			service: service,
			l:       cMux.Match(cmux.PrefixMatcher(string(uint8(5)))),
		}
		go c.Start()
	}
	return
}
